From 1349056112da56368e1eab7f9d724a70fc50943f Mon Sep 17 00:00:00 2001 From: Paul Donald Date: Thu, 7 Nov 2024 21:21:07 +0100 Subject: [PATCH] luci-mod-network: implement Virtual Routing and Forwarding (VRF) options VRF in netifd is now in main. See: https://github.com/openwrt/netifd/pull/38/ https://github.com/openwrt/openwrt/commit/15c2ca0a834752cc9505751fc6d2f51861d34dfd VRF netifd management was added to 24.10 in https://github.com/openwrt/openwrt/pull/19125 Signed-off-by: Paul Donald --- .../luci-static/resources/tools/network.js | 25 ++++++++++++++----- .../resources/view/network/interfaces.js | 19 +++++++++++++- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/modules/luci-mod-network/htdocs/luci-static/resources/tools/network.js b/modules/luci-mod-network/htdocs/luci-static/resources/tools/network.js index 82696cf1fb..d106e7cdd0 100644 --- a/modules/luci-mod-network/htdocs/luci-static/resources/tools/network.js +++ b/modules/luci-mod-network/htdocs/luci-static/resources/tools/network.js @@ -440,7 +440,7 @@ return baseclass.extend({ return s.taboption(tabName, optionClass, optionName, optionTitle, optionDescription); }, - addDeviceOptions: function(s, dev, isNew) { + addDeviceOptions: function(s, dev, isNew, rtTables) { var parent_dev = dev ? dev.getParent() : null, devname = dev ? dev.getName() : null, o, ss; @@ -451,8 +451,10 @@ return baseclass.extend({ s.tab('bridgevlan', _('Bridge VLAN filtering')); o = this.replaceOption(s, 'devgeneral', form.ListValue, 'type', _('Device type'), - !L.hasSystemFeature('bonding') && isNew ? ''+ - _('For bonding, install %s').format('kmod-bonding') + '' : null); + (!L.hasSystemFeature('bonding') && isNew ? ''+ + _('For bonding, install %s').format('kmod-bonding') + '
' : '') + + (!L.hasSystemFeature('vrf') && isNew ? ''+ + _('For VRF, install %s').format('kmod-vrf') + '
' : '')); o.readonly = !isNew; o.value('', _('Network device')); if (L.hasSystemFeature('bonding')) { @@ -463,8 +465,11 @@ return baseclass.extend({ o.value('8021ad', _('VLAN (802.1ad)')); o.value('macvlan', _('MAC VLAN')); o.value('veth', _('Virtual Ethernet')); + if (L.hasSystemFeature('vrf') && L.hasSystemFeature('netifd_vrf')) { + o.value('vrf', _('VRF device')); + } o.validate = function(section_id, value) { - if (value == 'bonding' || value == 'bridge' || value == 'veth') + if (value == 'bonding' || value == 'bridge' || value == 'veth' || value == 'vrf') updatePlaceholders(this.section.getOption('name_complex'), section_id); return true; @@ -972,7 +977,7 @@ return baseclass.extend({ o.datatype = 'uinteger'; o.depends({'type': 'bonding', 'monitor_mode': 'mii'}); - o = this.replaceOption(s, 'devgeneral', widgets.DeviceSelect, 'ifname_multi-bridge', _('Bridge ports')); + o = this.replaceOption(s, 'devgeneral', widgets.DeviceSelect, 'ifname_multi-bridge', dev?.getType() == 'bridge' ? _('Bridge ports'): _('Ports')); o.size = 10; o.rmempty = true; o.multiple = true; @@ -998,7 +1003,8 @@ return baseclass.extend({ return (!parent_dev || parent_dev.getName() != bridge_name); }; - o.description = _('Specifies the wired ports to attach to this bridge. In order to attach wireless networks, choose the associated interface as network in the wireless settings.') + o.description = dev?.getType() == 'bridge' ? _('Specifies the wired ports to attach to this bridge. In order to attach wireless networks, choose the associated interface as network in the wireless settings.'): + _('Specifies the devices to attach to this VRF. In order to attach wireless networks, choose the associated interface as network in the wireless settings.'); o.onchange = function(ev, section_id, values) { ss.updatePorts(values); @@ -1007,6 +1013,13 @@ return baseclass.extend({ }); }; o.depends('type', 'bridge'); + o.depends('type', 'vrf'); + + o = this.replaceOption(s, 'devgeneral', form.Value, 'table', _('Routing table')); + rtTables.forEach((rtTable) => { + o.value(rtTable[1], '%s (%d)'.format(rtTable[1], rtTable[0])); + }) + o.depends('type', 'vrf'); o = this.replaceOption(s, 'devgeneral', form.Flag, 'bridge_empty', _('Bring up empty bridge'), _('Bring up the bridge interface even if no ports are attached')); o.default = o.disabled; diff --git a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js index c59bc08abd..1837aa08f8 100644 --- a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js +++ b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js @@ -1400,7 +1400,7 @@ return view.extend({ var isNew = (uci.get('network', s.section, 'name') == null), dev = getDevice(s.section); - nettools.addDeviceOptions(s, dev, isNew); + nettools.addDeviceOptions(s, dev, isNew, rtTables); }; s.handleModalCancel = function(map /*, ... */) { @@ -1473,6 +1473,9 @@ return view.extend({ case 'veth': return 'veth'; + case 'vrf': + return 'vrf'; + case 'wifi': case 'alias': case 'switch': @@ -1508,6 +1511,9 @@ return view.extend({ case 'veth': return _('Virtual Ethernet'); + case 'vrf': + return _('Virtual Routing and Forwarding (VRF)'); + default: return _('Network device'); } @@ -1569,6 +1575,17 @@ return view.extend({ _('This prefix is randomly generated at first install.')); o.datatype = 'cidr6'; + const l3mdevhelp1 = _('%s services running on this device in the default VRF context (ie., not bound to any VRF device) shall work across all VRF domains.'); + const l3mdevhelp2 = _('Off means VRF traffic will be handled exclusively by sockets bound to VRFs.'); + + o = s.option(form.Flag, 'tcp_l3mdev', _('TCP Layer 3 Master Device (tcp_l3mdev) accept'), + l3mdevhelp1.format('TCP') + '
' + + l3mdevhelp2); + + o = s.option(form.Flag, 'udp_l3mdev', _('UDP Layer 3 Master Device (udp_l3mdev) accept'), + l3mdevhelp1.format('UDP') + '
' + + l3mdevhelp2); + o = s.option(form.ListValue, 'packet_steering', _('Packet Steering'), _('Enable packet steering across CPUs. May help or hinder network speed.')); o.value('0', _('Disabled')); o.value('1',_('Enabled')); -- 2.30.2